home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / benchmarks / itc / sas / lexer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-08-30  |  15.4 KB  |  678 lines

  1. /* $Header: lexer.c,v 3.6 88/10/18 16:34:32 hilfingr Exp $ */
  2.  
  3. /* Lexical analysis for SPUR assembler (sas) */
  4.  
  5. /* Copyright (c) 1987 by the Regents of the University of California.  All 
  6.  * rights reserved.  
  7.  *
  8.  * Author: P. N. Hilfinger
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include "a.out.h"
  15. #include "sas.h"
  16. #include "parser.h"
  17.  
  18. #define USERSYMTABLESIZE 1031
  19. #define PREDEFINEDSYMTABLESIZE 211
  20. #define BLOCKSIZE 4096
  21.  
  22.     /* Table of symbols defined in input */
  23. static symbolType *userSymTable[USERSYMTABLESIZE];
  24.  
  25.    /* Table of predefined symbols */
  26. static symbolType *predefinedSymTable[PREDEFINEDSYMTABLESIZE];
  27.  
  28. extern YYSTYPE yylval;    /* Global used to communicate semantic information to parser. */
  29.  
  30. struct genericInitTable {  /* General form of initialization structures */
  31.     char  *string;
  32.     int   type;
  33.     int   id;
  34. };
  35.  
  36. static struct genericInitTable predefinedSymbolInitTable[] = {
  37. #   include "predefines.i"
  38. #   include "opcodes.i"
  39.     { ".globl", _globl, 0 },
  40.     { ".extern", _extern, 0 },
  41.     { ".long", _long, 0 },
  42.     { ".word", _word, 0},
  43.     { ".byte", _byte, 0},
  44.     { ".single", _single, 0},
  45.     { ".double", _double, 0 },
  46.     { ".ascii", _ascii, 0 },
  47.     { ".asciz", _asciz, 0 },
  48.     { ".align", _align, 0},
  49.     { ".comm", _comm, 0},
  50.     { ".lcomm", _lcomm, 0},
  51.     { ".scomm", _scomm, 0},
  52.     { ".slcomm", _slcomm, 0},
  53.     { ".text", _text0, 0},
  54.     { ".text0", _text0, 0},
  55.     { ".text1", _text1, 0}, 
  56.     { ".text2", _text2, 0},
  57.     { ".data", _data0, 0},
  58.     { ".data0", _data0, 0},
  59.     { ".data1", _data1, 0},
  60.     { ".data2", _data2, 0},
  61.     { ".sdata", _sdata0, 0},
  62.     { ".sdata0", _sdata0, 0},
  63.     { ".sdata1", _sdata1, 0},
  64.     { ".set", _set, 0},
  65.     { ".org", _org, 0},
  66.     { ".space", _space, 0},
  67.     { ".stabs", _stabs, 0},
  68.     { ".stabn", _stabn, 0},
  69.     { ".stabd", _stabd, 0},
  70.     { NULL, 0, 0 }
  71. };
  72.  
  73. static bool commandSet = FALSE;        /* TRUE iff module initialized */
  74. static bool atLineStart;        /* TRUE iff at start of line in input */
  75.  
  76. static bool blank[128];            /* blank[c] iff c is a blank character. */
  77. static bool idChar[128];        /* idChar[c] iff c can appear after first char 
  78.                      * of an identifier. */
  79. static char class[128];            /* Classes of the charcters:
  80.                        'A':  Letters
  81.                        ',':  Various single-character punctuation.
  82.                        '0':  Digits
  83.                        '+':  + or -
  84.                        other characters are their own class
  85.                      */
  86.         /* Symbol table manipulation */
  87.  
  88. int
  89. hash(s, tableSize)
  90.      char *s;
  91.      int tableSize;
  92.      /* Produce a hashed value for s into a table of size tableSize.  Algorithm due to
  93.       * P. J. Weinberger, as published in Aho, Sethi, Ullman. */
  94. {
  95.     char *p;
  96.     unsigned h = 0, g;
  97.  
  98.     for (p = s; *p != '\0'; p++) {
  99.     h = (h << 4) + *p;
  100.         g = h & 0xf0000000;
  101.     if (g != 0)
  102.         h ^= (g >> 24) ^ g;
  103.     }
  104.     return (int) (h % tableSize);
  105. }
  106.  
  107. int         nextId;        /* Next user symbol id. */
  108. symbolType     *lastSym;   /* Last created symbol */
  109. symbolType    *firstSym;
  110.  
  111. void
  112. assignId(s)
  113.      symbolType *s;
  114.      /* Assign next ordinal in sequence to s and link into list of user 
  115.       * symbols, if s is new. */
  116. {
  117.     if (s->id != -1) return;
  118.     s -> id = nextId++;
  119.     if (firstSym == NULL)
  120.     firstSym = lastSym = s;
  121.     else lastSym = lastSym -> next = s;
  122.     s -> next = NULL;
  123. }
  124.  
  125. symbolType *
  126. newSymbol(s, type, other, desc)
  127.      char *s;
  128.      unsigned int type, other, desc;
  129.      /* Create a new, uninterned symbol with given string, n_type,
  130.       * n_other, and n_desc fields.  */
  131. {
  132.     symbolType *e = 
  133.     (symbolType *) malloc((unsigned) 
  134.                   (sizeof(symbolType) + strlen((char *) s)));
  135.  
  136.     (void) strcpy(e -> string, (char *) s);
  137.     e -> type = type, e -> other = other, e -> desc = desc;
  138.     e -> id = -1, e -> value = 0, e -> link = NULL, e -> segment = -1;
  139.     return e;
  140. }
  141.  
  142. symbolType *
  143. intern(s,hashTable,tableSize,addp)
  144.      char *s;
  145.      symbolType *hashTable[];
  146.      int tableSize, addp;
  147.  
  148.      /* Return table entry for symbol s in given hashTable of given
  149.       * tableSize.  If addp is false, return null if entry not
  150.       * initially present. */
  151. {
  152.     int h;
  153.     symbolType *e = (symbolType *) NULL;
  154.  
  155.     if (s[0] != '\0') {
  156.     h = hash(s, tableSize);
  157.     
  158.     for (e = hashTable[h]; e != NULL && strcmp(s, e->string) != 0;
  159.          e = e->link);
  160.     }
  161.     if (e == NULL && addp) {
  162.     e = newSymbol((char *) s, N_UNDF, 0, 0);
  163.     e->link = hashTable[h], hashTable[h] = e;
  164.     }
  165.  
  166.     return e;
  167. }
  168.  
  169. void
  170. initTable(table, tableSize, initTable)
  171.      symbolType *table[];
  172.      int tableSize;
  173.      struct genericInitTable initTable[];
  174.      /* Initialize table (with tableSize entries) from the list of 
  175.       * symbols and associated data in initTable.
  176.       */
  177. {
  178.     struct genericInitTable *c;
  179.  
  180.     for (c = initTable; c->string != NULL; c++) {
  181.     symbolType *e = intern(c->string, table, tableSize, TRUE);
  182.     e->id = c->id;
  183.     e->type = (int) c->type;
  184.     }
  185. }
  186.  
  187.         /* Input */
  188.  
  189. /* It is assumed that no line will be longer than BLOCKSIZE.  If a line is 
  190.  * longer than BLOCKSIZE, or if the last line of a file is improperly 
  191.  * terminated, the lexer may either report an error and insert a newline or 
  192.  * do the right thing. */
  193.  
  194. static char inputBuffer[BLOCKSIZE*2+1];    /* Space for two blocks of input. */
  195. static char *nextin;            /* Position of next unprocessed 
  196.                        input char. */
  197. static char *lastin;            /* Address of character beyond the
  198.                        end of the current input buffer. */
  199.  
  200. int
  201. read2(where, len)
  202.      char *where;
  203.      int len;
  204.      /* Read len characters into where, returning number actually read, 
  205.       * or -1 in case of error. The number returned is always len unless 
  206.       * the end of file is reached or there is an error. */
  207. {
  208.     int n = len, m;
  209.  
  210.     while (n > 0) {
  211.     m = read(0, where, n);
  212.     if (m == -1) return -1;
  213.     if (m == 0) return len-n;
  214.     n -= m;
  215.     where += m;
  216.     }
  217.     return len;
  218. }
  219.  
  220. void
  221. initInput()
  222.      /* Called at beginning of each source file to initialize input */
  223. {
  224.     int len;
  225.  
  226.     nextin = inputBuffer;
  227.     len = read2(inputBuffer, BLOCKSIZE*2);
  228.     if (len == -1) {
  229.     ErrorMsg  "Unable to read input." EndMsg;
  230.     exit2(1);
  231.     }
  232.     lastin = nextin + len;
  233.     *lastin = '\n';
  234. }
  235.  
  236. bool
  237. checkInput()
  238.      /* If necessary, read more input from standard input.  Returns TRUE iff 
  239.       * there is more input. */
  240. {
  241.     if (nextin - inputBuffer >= BLOCKSIZE) {
  242.     int len;
  243.  
  244.     (void) bcopy(inputBuffer + BLOCKSIZE, inputBuffer, BLOCKSIZE);
  245.     nextin -= BLOCKSIZE;
  246.     lastin -= BLOCKSIZE;
  247.     len = read2(inputBuffer + BLOCKSIZE, BLOCKSIZE);
  248.     if (len == -1) {
  249.         ErrorMsg "Read failed." EndMsg;
  250.         exit2(1);
  251.     }
  252.     lastin += len;
  253.     *lastin = '\n';
  254.     }
  255.     return (nextin < lastin);
  256. }
  257.             /* Initialization */
  258.  
  259. void
  260. initLexer()
  261. {
  262.     int i;
  263.  
  264.     initInput();
  265.     linecount = 1;
  266.     nextId = 0;
  267.     firstSym = lastSym = NULL;
  268.     atLineStart = TRUE;
  269.  
  270.     for (i = 0; i < USERSYMTABLESIZE; i++) {
  271.     symbolType *e = userSymTable[i];
  272.  
  273.     while ((e = userSymTable[i]) != NULL) {
  274.         userSymTable[i] = e->link;
  275.         (void) free((char *) e);
  276.     }
  277.     }
  278.  
  279.     if (! commandSet) {
  280.     int c;
  281.     commandSet = TRUE;
  282.  
  283.     initTable(predefinedSymTable, PREDEFINEDSYMTABLESIZE, 
  284.           (struct genericInitTable *) predefinedSymbolInitTable);
  285.  
  286.     for (c = 0; c < 128; c++) {
  287.         blank[c] = (c == ' ' || c == '\t' || c == '\f');
  288.         class[c] = 
  289.         isalpha(c) || c == '_' ? 'A' :
  290.         isdigit(c)             ? '0' :
  291.         c == '+' || c == '-'   ? '+' :
  292.         c;
  293.         idChar[c] = isalpha(c) || isdigit(c) || c == '_' || c == '.';
  294.     }
  295.     class['='] = class['^'] = class[':'] = class['~'] = class['&'] =
  296.          class[';'] = class['*'] = class['/'] = class['('] = class[')'] =
  297.          class['|'] = class['$'] = class['%'] = ',';
  298.     }
  299. }
  300.             /* Main lexical analysis routines */
  301.  
  302. void
  303. readString()
  304.      /* Read string starting at nextin, setting yylval appropriately.  Advances
  305.       * nextin. */
  306. {
  307.     char *inputStart = nextin+1;
  308.     char *str;
  309.     /* *stringBuffer and stringBufferLength hold a string constant until the 
  310.      * next string literal.  stringBufferLength is the size of the
  311.      * area pointed to by stringBuffer.  It is expanded as needed to hold
  312.      * the largest string read by readString. */
  313.     static char *stringBuffer = NULL;
  314.     static int stringBufferLength = 0;
  315.  
  316.     str = inputStart;
  317.     for (nextin += 1; *nextin != '"' && *nextin != '\n'; nextin++) {
  318.     if (*nextin == '\\') {
  319.         nextin++;
  320.         switch (*nextin) {
  321.         default:
  322.         *str++ = *nextin; break;
  323.         case 'b':
  324.         *str++ = '\b'; break;
  325.         case 'f':
  326.         *str++ = '\f'; break;
  327.         case 'n': 
  328.         *str++ = '\n'; break;
  329.         case 'r': 
  330.         *str++ = '\r'; break;
  331.         case 't':
  332.         *str++ = '\t'; break;
  333.         case 'v':
  334.         *str++ = '\v'; break;
  335.         case '0':
  336.         case '1':
  337.         case '2':
  338.         case '3':
  339.         case '4':
  340.         case '5':
  341.         case '6':
  342.         case '7':
  343.         {
  344.             int i,n;
  345.             for (i = 1, n = 0; 
  346.              i <= 3 && *nextin >= '0' && *nextin <= '7'; 
  347.              n = n*8 + *nextin - '0', i++, nextin++);
  348.             *str++ = (char) n;
  349.             nextin--;
  350.         }
  351.         break;
  352.         }
  353.     }
  354.     else *str++ = *nextin;
  355.     }
  356.  
  357.     if (*nextin != '"') {
  358.     ErrorMsg "Runaway string." EndMsg;
  359.     }
  360.     else nextin++;
  361.  
  362.     *str = '\0';
  363.     yylval.string.len = str - inputStart;
  364.     if (yylval.string.len >= stringBufferLength) {
  365.     if (stringBuffer != NULL) 
  366.         (void) free(stringBuffer);
  367.     stringBufferLength = yylval.string.len+1;
  368.     stringBuffer = (char *) malloc((unsigned) stringBufferLength);
  369.     }
  370.     (void) strcpy(stringBuffer, inputStart);
  371.     yylval.string.str = (char *) stringBuffer;
  372. }
  373.  
  374. int
  375. readNum()
  376.      /* Read longest legal number or additive operator (+ or -) from nextin.
  377.       * Put value in yylval and return syntactic type. Advances nextin. */
  378. {
  379.     char *p = nextin,
  380.          t;
  381.  
  382.     /* The following FSR recognizes decimal, octal, and hexadecimal integers,
  383.      * signed and unsigned real numbers, + and - operators, and numeric 
  384.      * temporary labels. */
  385.  
  386. #define STATE(label) label:
  387. #define TRANS(c, state) if (*p == (c)) { p++; goto state; }
  388. #define DTRANS(state)    goto state;
  389. #define CTRANS(func, state) if (func(*p)) { p++; goto state; }
  390. #define RETFIRST  yylval.num = *nextin; return (*nextin++);
  391. #define RETINT(format, type) \
  392.     t = *p; \
  393.     *p = '\0'; \
  394.     (void) sscanf(nextin, format, &yylval.num); \
  395.     nextin = p; \
  396.     *p = t; \
  397.     return type;
  398. #define RETREAL \
  399.     yylval.string.len = p - nextin; \
  400.     yylval.string.str = nextin; \
  401.     nextin = p; \
  402.     return FLOATCONST;
  403.  
  404. /* STATE(start) */
  405.     TRANS('+', _signed)
  406.     TRANS('-', _signed)
  407.     TRANS('0', leadingZero)
  408.     DTRANS(unsignedInt)
  409.  
  410. STATE(unsignedInt)
  411.     CTRANS(isdigit, unsignedInt)
  412.     TRANS('f', fwdRef)
  413.     TRANS('b', bckwdRef)
  414.     TRANS('.', okReal)
  415.     RETINT("%d", INTCONST);
  416.  
  417. STATE(fwdRef)
  418.     RETINT("%d", FWDNUMTEMPREF)
  419.  
  420. STATE(bckwdRef)
  421.     RETINT("%d", BCKWDNUMTEMPREF)
  422.  
  423. STATE(_signed)
  424.     CTRANS(isdigit, signedInt)
  425.     RETFIRST
  426.  
  427. STATE(signedInt)
  428.     CTRANS(isdigit, signedInt)
  429.     TRANS('.', okReal)
  430.     RETFIRST
  431.  
  432. STATE(okReal)
  433.     CTRANS(isdigit, okReal)
  434.     TRANS('e', exponent)
  435.     TRANS('E', exponent)
  436.     RETREAL
  437.  
  438. STATE(exponent)
  439.     TRANS('+', exponent2)
  440.     TRANS('-', exponent2)
  441.     CTRANS(isdigit, exponent3)
  442.     RETFIRST
  443.  
  444. STATE(exponent2)
  445.     CTRANS(isdigit, exponent3)
  446.     RETFIRST
  447.  
  448. STATE(exponent3)
  449.     CTRANS(isdigit, exponent3)
  450.     RETREAL
  451.  
  452. STATE(leadingZero)
  453.     CTRANS(isdigit, octalOrReal)
  454.     TRANS('x', hex1)
  455.     TRANS('X', hex1)
  456.     TRANS('f', fwdRef)
  457.     TRANS('b', bckwdRef)
  458.     TRANS('.', okReal)
  459.     RETINT("%d",INTCONST)
  460.  
  461. STATE(octalOrReal)
  462.     CTRANS(isdigit, octalOrReal)
  463.     TRANS('.', okReal)
  464.     RETINT("%o",INTCONST)
  465.  
  466. STATE(hex1)
  467.     CTRANS(isxdigit, hex2)
  468.     RETFIRST
  469.  
  470. STATE(hex2)
  471.     CTRANS(isxdigit, hex2)
  472.     nextin += 2;
  473.     RETINT("%x",INTCONST)
  474.  
  475. #undef STATE
  476. #undef TRANS
  477. #undef DTRANS
  478. #undef CTRANS
  479. #undef RETFIRST
  480. #undef RETINT
  481. #undef RETREAL
  482. }
  483.  
  484. int
  485. yylex()
  486.      /* Read next lexeme from input.  Return its lexical type, and, if its
  487.       * type designates a class of more than one lexeme, return additional data
  488.       * in yylval.
  489.       */
  490. {
  491.     while (TRUE) {
  492.     if (!checkInput()) return 0;
  493.  
  494.     if (blank[*nextin]) atLineStart = FALSE;
  495.     while (blank[*nextin]) nextin++;
  496.  
  497.     switch (class[*nextin]) {
  498.     case '\n':
  499.         linecount++; nextin++;
  500.         atLineStart = TRUE;
  501.         return EOLN;
  502.     case '/':
  503.         atLineStart = FALSE;
  504.         if (*(++nextin) == '*') {
  505.         while (TRUE) {
  506.             while (*nextin != '\n' && *nextin != '*') nextin++;
  507.             if (*nextin == '\n') {
  508.             linecount++;
  509.             if (nextin >= lastin) {
  510.                 ErrorMsg "Line too long; newline inserted." EndMsg;
  511.                 (void) checkInput();
  512.             }
  513.             nextin++;
  514.             if (!checkInput()) {
  515.                 ErrorMsg "Unterminated comment." EndMsg;
  516.                 return 0;
  517.             }
  518.             }
  519.             else /* *nextin == '*' */ {
  520.             if (*(++nextin) == '/') {
  521.                 nextin++;
  522.                 break;
  523.             }
  524.             }
  525.         }
  526.         }
  527.         else {
  528.         yylval.num = (unsigned int) '/';
  529.         return '/';
  530.         }
  531.         continue;
  532.     case '#':
  533.         if (atLineStart) {
  534.         char *nextnewline;
  535.         char dummy;
  536.         int num;
  537.  
  538.         for (nextnewline = nextin; *nextnewline != '\n'; nextnewline++)
  539.             ;
  540.         *nextnewline = '\0';
  541.         num = sscanf(nextin, "# %*d \"%*[^\"]%c", &dummy);
  542.         if (num != 1 || dummy != '\"') {
  543.             ErrorMsg "Invalid preprocessor command or comment." EndMsg;
  544.         }
  545.         else {
  546.             (void) sscanf(nextin, "# %d \"%[^\"]", &linecount, 
  547.                   filename);
  548.             linecount--;
  549.         }
  550.         *nextnewline = '\n';
  551.         }
  552.         atLineStart = FALSE;
  553.         while (*(++nextin) != '\n');
  554.         if (lastin == nextin) {
  555.         ErrorMsg "Line too long; newline inserted." EndMsg;
  556.         (void) checkInput();
  557.         }
  558.         continue;
  559.     case ',':    /* Random punctuation */
  560.         atLineStart = FALSE;
  561.         yylval.num = (unsigned int) *nextin;
  562.         nextin++;
  563.         return yylval.num;
  564.     case '<':
  565.         atLineStart = FALSE;
  566.         if (nextin[1] != '<') break;
  567.         nextin += 2;
  568.         yylval.num = LSHIFT;
  569.         return LSHIFT;
  570.     case '>':
  571.         atLineStart = FALSE;
  572.         if (nextin[1] != '>') break;
  573.         nextin += 2;
  574.         yylval.num = RSHIFT;
  575.         return RSHIFT;
  576.     case '0':
  577.     case '+':
  578.         atLineStart = FALSE;
  579.         return readNum();
  580.     case '"':
  581.         atLineStart = FALSE;
  582.         readString();
  583.         return STRINGCONST;
  584.     case '@':
  585.         {
  586.         char *p, *end;
  587.         char t;
  588.         int lexType;
  589.  
  590.         atLineStart = FALSE;
  591.         if (class[nextin[1]] != 'A') {
  592.             nextin++;
  593.             ErrorMsg "Ill-formed temporary label." EndMsg;
  594.             continue;
  595.         }
  596.  
  597.         for (p = nextin+1; idChar[*p]; p++);
  598.         end = p;
  599.         
  600.         if (p[0] == '$' && p[1] == 'w') 
  601.             p += 2;
  602.         else {
  603.             for ( ; blank[*p]; p++);
  604.         }
  605.  
  606.             if (*end == '$' || *p != ':') {
  607.             end--;
  608.             if (end[0] == 'f') lexType = FWDTEMPREF;
  609.             else if (end[0] == 'b') lexType = BCKWDTEMPREF;
  610.             else {
  611.             ErrorMsg
  612.                 "Temporary label assumed to be forward." 
  613.                 EndMsg;
  614.             end++;
  615.             lexType = FWDTEMPREF;
  616.             }
  617.         }
  618.         else lexType = TEMPLABEL;
  619.  
  620.         t = end[0]; end[0] = '\0';
  621.         yylval.sym = intern(nextin, userSymTable, 
  622.                     USERSYMTABLESIZE, TRUE);
  623.         end[0] = t;
  624.  
  625.         nextin = p;
  626.         return lexType;
  627.         }
  628.     case '.':
  629.         atLineStart = FALSE;
  630.         if (!idChar[nextin[1]]) {
  631.         nextin++;
  632.         yylval.num = '.';
  633.         return '.';
  634.         }
  635.         /* Else, fall through */
  636.     case 'A':
  637.         {
  638.         symbolType *sym;
  639.         int tokenType;
  640.         char *p,t;
  641.         
  642.         atLineStart = FALSE;
  643.         for (p = nextin; idChar[*p]; p++);
  644.         if (p[0] == '$' && p[1] == 'w') p += 2;
  645.         t = *p;
  646.         *p = '\0';
  647.  
  648.         sym = intern(nextin, predefinedSymTable, 
  649.                  PREDEFINEDSYMTABLESIZE, FALSE);
  650.  
  651.         if (sym != NULL) {
  652.             yylval.num = sym -> id;
  653.             nextin = p; *p = t;
  654.             return sym -> type;
  655.         }
  656.         if (p[-2] == '$' && p[-1] == 'w') {
  657.             tokenType = WORDID;
  658.             p[-2] = '\0';
  659.         }
  660.         else tokenType = ID;
  661.         yylval.sym = intern(nextin,userSymTable,USERSYMTABLESIZE,TRUE);
  662.         *p = t; nextin = p;
  663.         
  664.         assignId(yylval.sym);
  665.         return(tokenType);
  666.         }
  667.     default:
  668.         atLineStart = FALSE;
  669.         break;
  670.     }
  671.  
  672.     ErrorMsg 
  673.         "Illegal character %c (%x) encountered.", *nextin, (unsigned) *nextin
  674.     EndMsg;
  675.     nextin++;
  676.     }
  677. }
  678.